package com.xiaobawang.knowledge.spider.service.impl;

import com.xiaobawang.knowledge.spider.config.EmailConfig;
import com.xiaobawang.knowledge.spider.exception.BusinessException;
import com.xiaobawang.knowledge.spider.forest.PingAnClient;
import com.xiaobawang.knowledge.spider.model.dto.EmailDTO;
import com.xiaobawang.knowledge.spider.model.entity.PingAnProduct;
import com.xiaobawang.knowledge.spider.service.EmailService;
import com.xiaobawang.knowledge.spider.service.PingAnProductService;
import com.xiaobawang.knowledge.spider.util.FileUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.springframework.stereotype.Service;

import java.io.File;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;

/**
 * @author synhard
 * @description 爬取中国平安在售保险产品文件
 * @date 2025/6/19 14:01
 * @email songxinhang2023@e-chinalife.com
 * @id 18101119
 * @phone 13001321080
 */
@Service
@Slf4j
public class PingAnProductServiceImpl implements PingAnProductService {

    @Resource
    private PingAnClient pingAnClient;

    private final EmailConfig emailConfig;

    private final EmailService emailService;

    public PingAnProductServiceImpl(EmailConfig emailConfig,
                            EmailService emailService) {
        this.emailConfig = emailConfig;
        this.emailService = emailService;
    }

    @Override
    public void crawl() {
        ChromeOptions options = new ChromeOptions();
        options.addArguments("--headless");
        options.addArguments("--disable-gpu");
        options.addArguments("--no-sandbox");
        WebDriver           driver   = new ChromeDriver(options);
        WebDriverWait       wait     = new WebDriverWait(driver, Duration.ofSeconds(15));
        List<PingAnProduct> products = new ArrayList<>();

        try {
            // 访问目标页面
            driver.get("https://life.pingan.com/gongkaixinxipilu/baoxianchanpinmulujitiaokuan.jsp");
            while (true) {
                // 等待数据加载
                wait.until(ExpectedConditions.presenceOfElementLocated(
                        By.id("dataTable")
                ));

                // 解析表格数据
                WebElement       table = driver.findElement(By.id("dataTable"));
                List<WebElement> rows  = table.findElements(By.tagName("tr"));

                for (WebElement row : rows) {
                    PingAnProduct product = parseRow(row);
                    if (product != null) {
                        products.add(product);
                    }
                }

                // 分页处理
                List<WebElement> nextButtons = driver.findElements(
                        By.xpath("//a[contains(text(),'下一页')]")
                );

                // 终止条件：没有下一页按钮或按钮被禁用
                if (nextButtons.isEmpty() ||           // 无按钮
                        !nextButtons.get(0).isEnabled() || // 按钮禁用
                        nextButtons.get(0).getAttribute("href") == null // 无href属性
                ) {
                    break;
                }

                // 点击下一页
                nextButtons.get(0).click();
                Thread.sleep(500); // 页面加载等待
            }

            // 获取每个产品文件的字节数组
            List<byte[]> fileByteArrList = this.getFileByteArray(products);
            // 构造每个产品文件名称
            List<String> fileNameList = this.getFileName(products);
            // 发送邮件
            try {
                List<File> zipParts = FileUtil.splitIntoZipFiles(fileByteArrList, fileNameList, 20 * 1024 * 1024);
                for (int i = 0; i < zipParts.size(); i++) {
                    File     part     = zipParts.get(i);
                    EmailDTO emailDTO = new EmailDTO();
                    emailDTO.setSubject("中国平安产品文件（分卷" + (i + 1) + "）");
                    emailDTO.setFile(part);
                    emailDTO.setContent("此邮件为分卷压缩包，共" + zipParts.size() + "部分，需全部下载后解压");
                    emailDTO.setTo(emailConfig.getSupervisorFileReceiver());
                    emailDTO.setFrom(emailConfig.getFrom());
                    emailService.sendEmail(emailDTO);
                    part.delete();
                }
            } catch (Exception ex) {
                log.error("邮件发送失败", ex);
                throw new BusinessException("邮件发送失败: " + ex.getMessage());
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        } finally {
            driver.quit();
        }
    }

    /**
     * @param products 产品列表
     * @return java.util.List<java.lang.String>
     * @author synhard
     * @description 获取平安保险文件名
     * @date 2025/6/19 13:57
     */
    private List<String> getFileName(List<PingAnProduct> products) {
        List<String> fileNameList = new ArrayList<>();
        for (PingAnProduct product : products) {
            fileNameList.add(product.getFileName() + "-" + product.getFileCode() + "-" + product.getPublishDate() + ".pdf");
        }
        return fileNameList;
    }

    private List<byte[]> getFileByteArray(List<PingAnProduct> products) {
        List<byte[]> fileByteArrList = new ArrayList<>();
        // 访问每个产品的条款的链接
        for (PingAnProduct product : products) {
            // 获取链接，生成文件对应的字节数组
            try {
                byte[] bytes = pingAnClient.getPingAnProductFile(product.getFileLink());
                fileByteArrList.add(bytes);
                Thread.sleep(500L);
            } catch (Exception ex) {
                log.error(ex.getMessage(), ex);
                throw new BusinessException(ex.getMessage());
            }
        }
        return fileByteArrList;
    }

    // 解析单行数据
    private PingAnProduct parseRow(WebElement row) {
        try {
            List<WebElement> cells = row.findElements(By.tagName("td"));
            if (cells.size() < 4) return null;

            // 0. 产品代码（第一个td）
            String fileCode = cells.get(0).getText().trim();

            // 1. 文件名称（第二个td）
            String fileName = cells.get(1).getText().trim();

            // 2. 文件链接（第三个td）
            String fileLink = cells.get(2).findElements(By.cssSelector("ul a.a_b")).get(0).getAttribute("href");

            // 3. 发布日期（第四个td）
            String publishDate = cells.get(3).getText().trim();

            return new PingAnProduct(fileCode, fileName, fileLink, publishDate);
        } catch (NoSuchElementException e) {
            return null;
        }
    }
}
